//#include "common.cpp"

#include "dbclass.h"

#include <mysql++.h>
using namespace mysqlpp;

#include <errno.h>
#include <query.h>

#include <result.h>

#include <sys/stat.h>

#include <fstream>

#include <iostream>
using namespace std;

//initiate connection obj conn and query obj qy first.
//conn connects to 'vigenere' automatically
//qy is associated to conn
dbclass::dbclass()
{
	if (connect_db("vigenere") == false)
	{
		cerr <<"error connecting the db server" <<endl;

		exit(-EAGAIN);
	}

}

dbclass::~dbclass()
{
	disconnect_db();
}

//push a data item into the db in phase 1
//if it already exists, increase the count by 1
int dbclass::insert_table_phase1(string table_name, char* _id, int _pos, int _num)
{
	//first determine if this data item already exists
	string query_str = "select * from ";

	query_str += table_name;
	query_str += " where id = ";

	sql_bigint id = 0;
	memcpy((char* )(&id), _id, _num);

	stringstream ss_id;
	ss_id <<id;

	query_str += ss_id.str();

	query_str += ";";

#ifdef __TRACE_BUG__

	cout <<query_str <<endl;

#endif

	Query qy = query(query_str);
	UseQueryResult res = qy.use();
	qy.reset();

	Row row = res.fetch_row();

	//if it's a brandnew item, just create an entry in this db
	//else update the existed item, increase the count by 1 and
	//record the position in pos
	if (row.empty() == true)
	{//if it's a new item
		query_str = "insert into ";

		query_str += table_name;
		query_str += "(id, count, pos_1) values(";


		query_str += ss_id.str();

		query_str += ", 1, ";

		stringstream ss_pos;
		ss_pos <<_pos;
		query_str += ss_pos.str();

		query_str += ");";

#ifdef __TRACE_BUG__

		cout <<query_str <<endl;

#endif

		qy.exec(query_str);

		return 1;
	}
	else
	{//if this item already exists

		//record the count
		int count = row["count"];
		count++;

		//use up the returned result, this is one reason that I
		//hate mysql++
		while (row = res.fetch_row())
		{

		}

		query_str = "update ";
		query_str += table_name;
		query_str += " SET count = count + 1, ";

		//record its position
		switch (count)
		{
			case 2:
			{
				query_str += "pos_2 = ";

				break;
			}
			case 3:
			{
				query_str += "pos_3 = ";

				break;
			}
			case 4:
			{
				query_str += "pos_4 = ";

				break;
			}
			case 5:
			{
				query_str += "pos_5 = ";

				break;
			}
			case 6:
			{
				query_str += "pos_6 = ";

				break;
			}
			case 7:
			{
				query_str += "pos_7 = ";

				break;
			}
			case 8:
			{
				query_str += "pos_8 = ";

				break;
			}
			case 9:
			{
				query_str += "pos_9 = ";

				break;
			}
			case 10:
			{
				query_str += "pos_10 = ";

				break;
			}
			case 11:
			{
				query_str += "pos_11 = ";

				break;
			}
			case 12:
			{
				query_str += "pos_12 = ";

				break;
			}
			case 13:
			{
				query_str += "pos_13 = ";

				break;
			}
			case 14:
			{
				query_str += "pos_14 = ";

				break;
			}
			case 15:
			{
				query_str += "pos_15 = ";

				break;
			}
			case 16:
			{
				query_str += "pos_16 = ";

				break;
			}
			case 17:
			{
				query_str += "pos_17 = ";

				break;
			}
			case 18:
			{
				query_str += "pos_18 = ";

				break;
			}
			case 19:
			{
				query_str += "pos_19 = ";

				break;
			}
			case 20:
			{
				query_str += "pos_20 = ";

				break;
			}
			case 21:
			{
				query_str += "pos_21 = ";

				break;
			}
			case 22:
			{
				query_str += "pos_22 = ";

				break;
			}
			default:
			{
				//cerr <<"pos_ten = " <<endl;
				//exit(-1);

				query_str += "pos_22 = ";
			}
		}

		stringstream ss_pos;
		ss_pos <<_pos;

		query_str += ss_pos.str();

		query_str += " WHERE id = ";

		query_str += ss_id.str();

		query_str += ";";

#ifdef __BUG_TRACE__

		cout <<query_str <<endl;
#endif

		qy.exec(query_str);
		qy.reset();

		//return count
		return count;
	}

	return 0;

}

//push a data item into db in phase two
//if the item already exists, increase the count by 1
int dbclass::insert_table_phase2(string table_name, char _id, int _pos)
{
	//first determine if this data item already exists
	string query_str = "select * from ";

	query_str += table_name;
	query_str += " where (id = ";

	sql_bigint id = 0;
	id += _id;

	stringstream ss_id;
	ss_id <<id;

	query_str += ss_id.str();

	query_str += " and pos = ";

	stringstream ss_pos;
	ss_pos <<_pos;

	query_str += ss_pos.str();

	query_str += ");";

#ifdef __TRACE_BUG__

	cout <<query_str <<endl;

#endif

	Query qy = query(query_str);
	UseQueryResult res = qy.use();
	qy.reset();

	Row row = res.fetch_row();

	//if it's a brandnew item, just create an entry in this db
	//else update the existed item, increase the count by 1 and
	//record the position in pos
	if (row.empty() == true)
	{//if it's a new item

		query_str = "insert into ";

		query_str += table_name;
		query_str += "(id, count, pos) values(";

		query_str += ss_id.str();

		query_str += ", 1, ";

		query_str += ss_pos.str();

		query_str += ");";

#ifdef __TRACE_BUG__

		cout <<query_str <<endl;

#endif

		qy.exec(query_str);
		qy.reset();

		return 1;
	}
	else
	{//it it already exists


		//record the count
		int count = row["count"];
		count++;

		//use up the returned result
		while (row = res.fetch_row())
		{

		}


		query_str = "update ";
		query_str += table_name;
		query_str += " set count = count + 1 ";

		query_str += "where (id = ";

		query_str += ss_id.str();

		query_str += " and pos = ";

		query_str += ss_pos.str();

		query_str += ");";

		qy.exec(query_str);
		qy.reset();

		//return the count
		return count;
	}

	return 0;
}


/*
double dbclass::com_sta(string cipher_txt, double k_p, double k_r)
{

	fstream infile;

	infile.open(cipher_txt.c_str(), ios::out|ios::in);

	if (infile.good() == false)
	{
		exit(-1);
	}

	drop_table("comp_stat");
	create_table_phase1("comp_stat");

	char buffer[4097];
	memset(buffer, 0, 4097);

	while (infile.good() == true)
	{

		infile.read(buffer, 4096);

		int count = infile.gcount();

		for (int i = 0; i < count; i++)
		{
			insert_table_phase1("comp_stat", buffer + i, i, 1);
		}
	}

	infile.close();


	string query_str = "select count from comp_stat;";


	Query qy = conn.query(query_str);
	UseQueryResult res = qy.use();
	qy.reset();

	double k_0 = 0.0;

	double tmp_op = 0.0;

	while(Row row = res.fetch_row())
	{
		tmp_op = row["count"];

		if (tmp_op > 0)
		{
			tmp_op = tmp_op * (tmp_op - 1);

			k_0 += tmp_op;
		}
	}

	struct stat st;
	stat(cipher_txt.c_str(), &st);

	k_0 /= st.st_size;
	k_0 /= (st.st_size - 1);

	drop_table("comp_stat");

	return ((k_p - k_r) / (k_0 - k_r));

}
*/

void dbclass::disconnect_db()
{
	disconnect();
}

bool dbclass::connect_db(string db_name)
{

	//connect to the 'vigenere' database
	connect(db_name.c_str(), "localhost", "hucat", "hucat2", 0);

	//judge the conncetion status
	return connected();

}

bool dbclass::create_table_phase1(string table_name)
{
	//create a table named 'word'
	string query_str = "create table if not exists ";

	query_str += table_name;
	query_str += "(";

	query_str += "id bigint, ";
	query_str += "count tinyint, ";

	query_str += "pos_1 int, ";
	query_str += "pos_2 int, ";
	query_str += "pos_3 int, ";
	query_str += "pos_4 int, ";
	query_str += "pos_5 int, ";
	query_str += "pos_6 int, ";
	query_str += "pos_7 int, ";
	query_str += "pos_8 int, ";
	query_str += "pos_9 int, ";
	query_str += "pos_10 int, ";
	query_str += "pos_11 int, ";
	query_str += "pos_12 int, ";
	query_str += "pos_13 int, ";
	query_str += "pos_14 int, ";
	query_str += "pos_15 int, ";
	query_str += "pos_16 int, ";
	query_str += "pos_17 int, ";
	query_str += "pos_18 int, ";
	query_str += "pos_19 int, ";
	query_str += "pos_20 int, ";
	query_str += "pos_21 int, ";
	query_str += "pos_22 int)";

	Query qy = query(query_str);

	return qy.exec();
}

bool dbclass::create_table_phase2(string table_name)
{
	//create a table named 'word'
	string query_str = "create table if not exists ";

	query_str += table_name;
	query_str += "(";

	query_str += "id bigint, ";
	query_str += "count int, ";
	query_str += "pos tinyint);";

	Query qy = query(query_str);

	return qy.exec();
}

void dbclass::drop_table(string table_name)
{
	string query_str = "drop table if exists ";

	query_str += table_name;
	query_str += ";";

	Query qy = query(query_str);

	qy.exec();
}
